﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace GTTSOfLibrary.MyException
{
    /// <summary>
    /// 泛型异常类
    /// <remarks>
    /// C#只允许自定义的类继承自系统异常类的基类：System.Exception，并且继承自System.Exception类的所有异常类型，
    /// 都必须是可被序列化的，这使得这些异常信息得以穿越AppDomain(比如Remoting服务端异常有可能需要返回到远程调用方，
    /// 这时就不得不穿越AppDomain)或者写入日志\数据库等
    /// </remarks>
    /// <example>
    /// 抛出/捕获自定义异常：
    /// <code>
    /// public void TestException() 
    /// {
    ///     try 
    ///     {
    ///         throw new Exception<DiskFullExceptionArgs>(
    ///              new DiskFullExceptionArgs(@"C:\"), "The disk is full");
    ///         }
    ///         catch (Exception<DiskFullExceptionArgs> ex) 
    ///         {
    ///            Console.WriteLine(ex.Message);
    ///         }
    /// }
    /// </code>
    /// </example>
    /// </summary>
    /// <typeparam name="TExceptionArgs">泛型参数</typeparam>
    [Serializable]
    public sealed class Exception<TExceptionArgs> : Exception, System.Runtime.Serialization.ISerializable
        where TExceptionArgs : ExceptionArgs
    {
        private const String c_args = "Args";
        private readonly TExceptionArgs m_args;

        public TExceptionArgs Args
        {
            get
            {
                return m_args;
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="message"></param>
        /// <param name="innerException"></param>
        public Exception(string message = null, Exception innerException = null)
            : this(null, message, innerException) { }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="args"></param>
        /// <param name="message"></param>
        /// <param name="innerException"></param>
        public Exception(TExceptionArgs args, String message = null, Exception innerException = null)
            : base(message, innerException) { m_args = args; }

        //该构造器用于反序列化，由于类是密封的，所以构造器是私有的
        //如果类不是密封的，这个构造器就应该是受保护的
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        private Exception(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            m_args = (TExceptionArgs)info.GetValue(c_args, typeof(TExceptionArgs));
        }

        //这个方法用于序列化，由于实现了ISerializable接口，所以它是公共的(该方法为ISerializable中定义的方法)
        //在Exception类中已有实现，此类继承了Exception，并重写了该方法在Exception中的实现
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue(c_args, m_args);
            base.GetObjectData(info, context);
        }

        /// <summary>
        /// （重载）异常信息
        /// </summary>
        public override string Message
        {
            get
            {
                String baseMsg = base.Message;
                return (m_args == null) ? base.Message : baseMsg + "(" + m_args.Message + ")";
            }
        }

        /// <summary>
        /// 重写Equals
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            Exception<TExceptionArgs> other = obj as Exception<TExceptionArgs>;
            if (obj == null)
            {
                return false;
            }
            return Object.ReferenceEquals(m_args, other.m_args) && base.Equals(obj);
        }

        /// <summary>
        /// 重写GetHashCode
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}
